﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Data.Objects.DataClasses;
using AvalonDock;
using System.Threading;
using ModeloGaleriaNET;
using CADs;
using Apache.NMS.ActiveMQ;
using Spring.Messaging.Nms.Listener;
using System.ComponentModel;
using Apache.NMS.ActiveMQ.Commands;
using System.Net;
using Apache.NMS;
using SeguridadGaleria;
using System.Reflection;
using ModeloGaleriaNET.Police;
using Newtonsoft.Json;


namespace GaleriaNET
{
    delegate void ActualizarDataGridCallBack();
    delegate void SetStatusCallback();
    delegate void SetTextIntoPanel();
    public partial class UserWindow : Window
    {
        private string[] permisos = new string[] {TiposRoles.VER_AUDITORIA, TiposRoles.VER_PRIVILEGIOS,
            TiposRoles.CAMBIAR_ACCESO_BD, TiposRoles.CAMBIAR_ACCESO_SERVIDOR, TiposRoles.CAMBIAR_ACCESO_UDDI,
            TiposRoles.CAMBIAR_SUSCRIPCION_TEMATICAS, TiposRoles.MODIFICAR_DATOS_USUARIO_PROPIO, 
            TiposRoles.MODIFICAR_DATOS_OTRO_USUARIO};
        private Usuario usuario;
        private UsuarioCAD uCAD;
        private Thread hiloActiveMQ;
        private List<ActiveMQSubscriber> subscribers;
        private BackgroundWorker workerjUDDI;
        private BackgroundWorker workerPeticiones;
        private BackgroundWorker workerPeticionesMQ;
        private BackgroundWorker workerTematicas;
        private Semaphore semaphore;
        private bool conectadojUDDI;
        private GestorMensajes gestor;
        private System.Timers.Timer activeMQTestTimer;
        private System.Timers.Timer jUDDITestTimer;
        private System.Timers.Timer publisherTimer;
        private Dictionary<string, bool> permisosDatos;
        private BackgroundWorker worker;
        private IAuditoria auditoria;
        private bool tematicasCambiadas;
        private GandalfService policia;

        public UserWindow()
        {
            InitializeComponent();
            usuario = null;
            uCAD = new UsuarioCAD();
            Init();
        }

        public UserWindow(Usuario u, UsuarioCAD ucad)
        {
            InitializeComponent();
            this.uCAD = ucad;
            usuario = u;
            Init();
        }

        public Usuario Usuario
        {
            get { return usuario; }
        }

        public UsuarioCAD UsuarioCAD
        {
            get { return uCAD; }
        }

        private void Init()
        {
            SSLValidator.OverrideValidation();
            policia = new GandalfService();
            auditoria = new AuditoriaBD();
            gestor = GestorMensajes.Instance;
            gestor.Documento = salidaDataGrid;
            hiloActiveMQ = new Thread(ListenerMQ);
            hiloActiveMQ.IsBackground = true;
            workerjUDDI = new BackgroundWorker();
            workerjUDDI.DoWork += workerjUDDI_DoWork;
            workerjUDDI.RunWorkerCompleted += workerjUDDI_RunWorkerCompleted;
            workerjUDDI.WorkerSupportsCancellation = true;
            workerPeticiones = new BackgroundWorker();
            workerPeticiones.DoWork += workerPeticiones_DoWork;
            workerPeticiones.RunWorkerCompleted += workerPeticiones_RunWorkerCompleted;
            workerPeticiones.WorkerSupportsCancellation = true;
            workerPeticionesMQ = new BackgroundWorker();
            workerPeticionesMQ.DoWork += workerPeticionesMQ_DoWork;
            workerPeticionesMQ.RunWorkerCompleted += workerPeticionesMQ_RunWorkerCompleted;
            workerPeticionesMQ.WorkerSupportsCancellation = true;
            workerTematicas = new BackgroundWorker();
            workerTematicas.DoWork += workerTematicas_DoWork;
            workerTematicas.RunWorkerCompleted += workerTematicas_RunWorkerCompleted;
            workerTematicas.WorkerSupportsCancellation = true;
            worker = new BackgroundWorker();
            worker.DoWork += worker_DoWork;
            worker.RunWorkerCompleted += worker_RunWorkerCompleted;
            semaphore = new Semaphore(0, 1);
            subscribers = new List<ActiveMQSubscriber>();
            activeMQTestTimer = new System.Timers.Timer(180000);
            activeMQTestTimer.Elapsed += ActiveMQTimer_CallBack;
            activeMQTestTimer.Enabled = true;
            jUDDITestTimer = new System.Timers.Timer(180000);
            jUDDITestTimer.Elapsed += jUDDITimer_CallBack;
            jUDDITestTimer.Enabled = true;
            publisherTimer = new System.Timers.Timer(150000);
            publisherTimer.Elapsed += publisherTimer_CallBack;
            publisherTimer.Enabled = true;
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            ((DataGrid)salidaDataGrid.Content).Columns.Insert(0, FindResource("resColumnaImg") as DataGridTemplateColumn);
            if (usuario != null)
            {
                // Si hay datos, arrancamos los hilos
                if (!ServerConnData.Instance.IsEmpty())
                {
                    SetStatusActiveMQ(null);
                    if (TematicasData.Instance.Tematicas != null &&
                        TematicasData.Instance.Tematicas.Count > 0)
                        hiloActiveMQ.Start();
                    else
                        workerTematicas.RunWorkerAsync();
                    
                    workerjUDDI.RunWorkerAsync();
                    if (gestor.HayPeticionesPendientes())
                        workerPeticiones.RunWorkerAsync();
                    if (gestor.HayPeticionesPendientesMQ())
                        workerPeticionesMQ.RunWorkerAsync();
                }

                lbUsuarioConectado.Content = usuario.Nombre + " " + usuario.Apellido1 + " " + usuario.Apellido2
                    + (usuario.EsAdministrador ? " (Administrador)" : " (Usuario)");
               // ShowPage<ucSubastas>();

                if (!worker.IsBusy)
                    worker.RunWorkerAsync();
            }
            else
            {
                lbUsuarioConectado.Content = "No hay conexión con la base de datos local";
                miClientes.IsEnabled = miObras.IsEnabled = miSubastas.IsEnabled = miUsuario.IsEnabled =
                    miAdministracion.IsEnabled = false;
            }

            #region Asignación del comando de ayuda
            miViewHelp.Command = ApplicationCommands.Help;
            miViewHelp.Header = ApplicationCommands.Help.Text;

            // Asignacion en un elemento padre (el objeto Window) ..
            this.CommandBindings
                .Add(new CommandBinding(ApplicationCommands.Help, HelpExecuted, HelpCanExecute));

            // Asignación en el propio elemento ..
            miViewHelp.CommandBindings
                .Add(new CommandBinding(ApplicationCommands.Help, HelpExecuted, HelpCanExecute));
            #endregion
        }

        private void worker_DoWork(object sender, DoWorkEventArgs e)
        {
            bool? value;

            permisosDatos = new Dictionary<string, bool>();
            foreach (string s in permisos)
            {
                value = ManejadorRoles.Instance.CanUse(s, usuario.PseudonimoLocal);
                if (value != null)
                    permisosDatos.Add(s, value.Value);
                else
                    MessageBox.Show(s);
            }
        }

        private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            bool value, value2;

            if (permisosDatos == null || permisosDatos.Count != permisos.Length)
            {
                Xceed.Wpf.Toolkit.MessageBox.Show("No se han podido obtener los permisos", "Error",
                    MessageBoxButton.OK, MessageBoxImage.Error);
                menuOpciones.IsEnabled = false;
            }
            else
            {
                permisosDatos.TryGetValue(TiposRoles.VER_AUDITORIA, out value);
                if (value == false)
                    miAuditoria.IsEnabled = false;

                permisosDatos.TryGetValue(TiposRoles.VER_PRIVILEGIOS, out value);
                if (value == false)
                    miVerGrupos.IsEnabled = miVerRolesUsuarios.IsEnabled = false;

                permisosDatos.TryGetValue(TiposRoles.CAMBIAR_ACCESO_BD, out value);
                if (value == false)
                    miBDLocal.IsEnabled = miBorrarDatosDB.IsEnabled = false;

                permisosDatos.TryGetValue(TiposRoles.CAMBIAR_SUSCRIPCION_TEMATICAS, out value);
                if (value == false)
                    miTematicas.IsEnabled = false;

                permisosDatos.TryGetValue(TiposRoles.CAMBIAR_ACCESO_SERVIDOR, out value);
                permisosDatos.TryGetValue(TiposRoles.CAMBIAR_ACCESO_UDDI, out value2);
                if (value == false && value2 == false)
                    miConfigServer.IsEnabled = miBorrarDatosServer.IsEnabled = false;

                permisosDatos.TryGetValue(TiposRoles.MODIFICAR_DATOS_USUARIO_PROPIO, out value);
                if (value == false)
                    miUsuario.IsEnabled = false;

                permisosDatos.TryGetValue(TiposRoles.MODIFICAR_DATOS_OTRO_USUARIO, out value);
                if (value == false)
                    miAdminUsuarios.IsEnabled = false;
            }
        }

        private void containerWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            StopThreads();
        }

        private void DataGrid_MouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            DataGrid grid;
            DataGridRow dgr;
            DocumentContent doc;
            ucSubastaPujaData uc;
            Subasta subasta;
            SubastaDeOtro subastaDeOtro;
            ActiveMQMapMessage mensaje;
            SubastaHasEstadoSubasta est;
            SubastaCAD sCAD;
            int zona;

            if (sender != null)
            {
                grid = sender as DataGrid;
                if (grid != null && grid.SelectedItems != null && grid.SelectedItems.Count == 1)
                {
                    dgr = grid.ItemContainerGenerator.ContainerFromItem(grid.SelectedItem) as DataGridRow;
                    if (dgr.Item is DataGridMessage && ((DataGridMessage)dgr.Item).Contenido != null
                        && (((DataGridMessage)dgr.Item).Contenido.Body.Contains("referencia") &&
                        gestor.activeMQContainsKey(((DataGridMessage)dgr.Item).Contenido.Body.GetLong("referencia"))))
                    {
                        doc = FindDocumentContent(typeof(ucSubastaPujaData));
                        if (doc == null)
                        {
                            mensaje = ((DataGridMessage)dgr.Item).Contenido;
                            sCAD = new SubastaCAD();
                            subasta = sCAD.GetSubastaByRefExterna(mensaje.Body.GetLong("referencia").ToString());
                            
                            if (subasta == null)
                            {
                                subastaDeOtro = new SubastaDeOtro();
                                subastaDeOtro.ReferenciaExterna = mensaje.Body.GetLong("referencia").ToString();
                                subastaDeOtro.NombreObra = mensaje.Body.GetString("tituloObra");
                                subastaDeOtro.AutorObra = mensaje.Body.GetString("autorObra");
                                subastaDeOtro.EstadoObra = mensaje.Body.GetInt("estadoConservacionObra") == 0 ? "original" : mensaje.Body.GetInt("estadoConservacionObra") == 1 ? "deteriorado" : "restaurado";
                                subastaDeOtro.AnyoObra = mensaje.Body.GetShort("añoObra");
                                subastaDeOtro.Autor = mensaje.Body.GetString("propietario");
                                subastaDeOtro.PrecioPartida = mensaje.Body.GetDouble("precioPartida");
                                subastaDeOtro.MaximoPujasPostor = mensaje.Body.GetInt("mpp");
                                subastaDeOtro.FechaInicio = DateTime.Parse(mensaje.Body.GetString("fechaInicio"));
                                subastaDeOtro.FechaLimite = DateTime.Parse(mensaje.Body.GetString("fechaFin"));
                               
                                // Las zonas horarias son provisionales
                                zona = Utilities.GetZonaHoraria();
                                subastaDeOtro.ZonaHorariaInicio = zona;
                                subastaDeOtro.ZonaInicioFin = zona;
                                
                                
                                subastaDeOtro.TipoNegociado = mensaje.Body.GetInt("negociado") == 0 ? "manual" : "automatico";
                                subastaDeOtro.Autor = mensaje.Body.GetString("propietario");
                                est = new SubastaHasEstadoSubasta();
                                est.EstadosSubasta = new EstadoSubastaCAD().GetEstadoPublicada();
                                est.FechaInicio = DateTime.UtcNow;

                                est.zonaFechaInicio = zona;

                                subastaDeOtro.SubastaHasEstadosSubasta.Add(est);
                                uc = new ucSubastaPujaData(subastaDeOtro);
                                uc.SubastaCAD = new SubastaCAD();
                                ShowPage<ucSubastaPujaData>(uc);
                            }
                            else
                            {
                                uc = new ucSubastaPujaData(subasta);
                                uc.SubastaCAD = sCAD;
                                ShowPage<ucSubastaPujaData>(uc);
                            }
                        }
                        else
                            MessageBox.Show("Ya hay abierta una ventana de datos de subasta. Ciérrela antes de abrir otra.",
                                "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                    }
                }
            }
        }

        public void ModificarUsuario(Usuario u)
        {
            usuario = u;
            lbUsuarioConectado.Content = usuario.Nombre + " " + usuario.Apellido1 + " " + usuario.Apellido2
                    + (usuario is Administrador ? " (Administrador)" : " (Usuario)");
        }

        #region Eventos de los distintos BackgroundWorkers y Timers
        private void publisherTimer_CallBack(object sender, System.Timers.ElapsedEventArgs e)
        {
            List<Subasta> subastas = null;
            SubastaCAD sCAD = null;
            MessageCrearSubasta mensaje;
            ucSubastas formSubastas;
            DocumentContent padre = null;

            Dispatcher.Invoke((ActualizarDataGridCallBack)delegate()
            {
                padre = (DocumentContent)(FindDocumentContent(typeof(ucSubastas)));
                sCAD = padre == null ? new SubastaCAD() : ((ucSubastas)padre.Content).SubastaCAD;
                subastas = sCAD.GetSubastasCreadas();
            }, null);
 
            if (subastas != null)
            {
                foreach (Subasta s in subastas)
                {
                    if (s.FechaInicio > DateTime.UtcNow)
                    {
                        s.ChangeState(new EstadoSubastaCAD().GetEstadoPublicada());
                        mensaje = new MessageCrearSubasta(s, salidaDataGrid, Usuario.Id);
                        AddMessage(mensaje);
                    }
                    else
                        s.ChangeState(new EstadoSubastaCAD().GetEstadoCancelada());

                    Dispatcher.Invoke((ActualizarDataGridCallBack)delegate()
                    {
                        if ((padre = (DocumentContent)(FindDocumentContent(typeof(ucSubastas)))) != null)
                        {
                            formSubastas = (ucSubastas)(padre.Content);
                            formSubastas.ActualizarDataGrid();
                        }
                    }, null);
                }
                sCAD.SaveChanges();
            }
        }

        private void jUDDITimer_CallBack(object sender, System.Timers.ElapsedEventArgs e)
        {
            if (!workerjUDDI.IsBusy)
            {
                SetStatusjUDDI(null);
                SetStatusjUDDI(jUDDIManager.Instance.GetAuthToken());
            }
        }

        private void ActiveMQTimer_CallBack(object sender, System.Timers.ElapsedEventArgs e)
        {
            try
            {
                SetStatusActiveMQ(null);
                TestActiveMQConnection();
                SetStatusActiveMQ(true);
            }
            catch (Exception)
            {
                StopActiveMQ();
                // Fallo al primer intento, buscamos con jUDDI
                if (jUDDIManager.Instance.UpdateURL())
                {
                    try
                    {
                        TestActiveMQConnection();
                        hiloActiveMQ = new Thread(ListenerMQ);
                        hiloActiveMQ.Start();
                    }
                    catch (Exception)
                    {
                        SetStatusActiveMQ(false);
                    }
                }
                else // jUDDI no está disponible tampoco, para los subscribers
                    SetStatusActiveMQ(false);
            }
        }

        private void buscarTematicas()
        {
            ModeloGaleriaNET.GaleriasQueries.GaleriasQueries query;
            ModeloGaleriaNET.GaleriasQueries.AuthInfo auth;
            ModeloGaleriaNET.GaleriasQueries.GaleriaProxy galeria;
            ModeloGaleriaNET.GaleriasQueries_Safe.UsuariosQueriesService querySafe;
            List<string> temas = null;
            authInfo authPolice;
            getTicketResponse ticketResponse;
            ModeloGaleriaNET.GaleriasQueries_Safe.ticketRequest request;
            ModeloGaleriaNET.GaleriasQueries_Safe.galeria galeriaSafe;

            query = new ModeloGaleriaNET.GaleriasQueries.GaleriasQueries();
            query.Timeout = (int)ServerConnData.Instance.TimeOut * 1000;
            auth = new ModeloGaleriaNET.GaleriasQueries.AuthInfo();
            auth.password = Utilities.EncriptarMD5(ServerConnData.Instance.Password);
            auth.pseudonimo = ServerConnData.Instance.User;

            if (ModeloGaleriaNET.Properties.Settings.Default.Seguridad == 2 || ModeloGaleriaNET.Properties.Settings.Default.Seguridad == 3)
            //if (ModeloGaleriaNET.Properties.Settings.Default.Seguridad == 4)
            {
                querySafe = new ModeloGaleriaNET.GaleriasQueries_Safe.UsuariosQueriesService();
                querySafe.Url = ModeloGaleriaNET.Properties.Settings.Default.Seguridad == 2 ?
                    ModeloGaleriaNET.Properties.Settings.Default.ModeloGaleriaNET_GaleriasQueries_Safe_UsuariosQueriesService :
                    ModeloGaleriaNET.Properties.Settings.Default.ModeloGaleriaNET_GaleriasQueries_Safe_UsuariosQueriesService_SSL;
                querySafe.Timeout = (int)ServerConnData.Instance.TimeOut * 1000;
                galeria = new ModeloGaleriaNET.GaleriasQueries.GaleriaProxy();
                // Encriptar cosas en JSON
                // Fin encriptar cosas en JSON

                policia.Url = ModeloGaleriaNET.Properties.Settings.Default.Seguridad == 2 ?
                    ModeloGaleriaNET.Properties.Settings.Default.ModeloGaleriaNET_Police_GandalfService :
                    ModeloGaleriaNET.Properties.Settings.Default.ModeloGaleriaNET_Police_GandalfService_SSL;
                policia.Timeout = (int)ModeloGaleriaNET.Properties.Settings.Default.TimeOut * 1000;
                authPolice = new authInfo();
                authPolice.pseudonimo = ServerConnData.Instance.User;
                authPolice.password = Utilities.EncriptarMD5(ServerConnData.Instance.Password);
                ticketResponse = policia.getTicket(authPolice);
                request = new ModeloGaleriaNET.GaleriasQueries_Safe.ticketRequest();
                request.ticketId = ticketResponse.ticketId;
                galeriaSafe = querySafe.getGaleria(request);
                temas = galeriaSafe.tematicasSuscritas.ToList();
            }
            else
            {
                query.Url = ModeloGaleriaNET.Properties.Settings.Default.Seguridad == 0 ? 
                    ModeloGaleriaNET.Properties.Settings.Default.ModeloGaleriaNET_WebReference_GaleriasQueries :
                    ModeloGaleriaNET.Properties.Settings.Default.ModeloGaleriaNET_WebReference_GaleriasQueries_SSL;
                galeria = query.getGaleria(auth);
                temas = galeria.tematicasSuscritas.ToList();
            }
            TematicasData.Instance.Save(temas);
        }

        private void workerTematicas_DoWork(object sender, DoWorkEventArgs e)
        {
            tematicasCambiadas = false;
            if (!ServerConnData.Instance.IsEmpty())
            {
                try
                {
                    Utilities.WriteMessageOnGrid(salidaDataGrid, "No hay información de temáticas en la aplicación. Obteniendo información del servidor...", DataGridMessage.TIPO_MENSAJE.INFO);
                    buscarTematicas();
                    Utilities.WriteMessageOnGrid(salidaDataGrid,
                        "Temáticas obtenidas correctamente del servidor", DataGridMessage.TIPO_MENSAJE.INFO);
                    hiloActiveMQ.Start();
                    tematicasCambiadas = true;
                }
                catch (Exception ex)
                {
                    while (ex != null)
                    {
                        Utilities.WriteMessageOnGrid(salidaDataGrid, ex.Message, DataGridMessage.TIPO_MENSAJE.WARNING);
                        ex = ex.InnerException;
                    }

                    Utilities.WriteMessageOnGrid(salidaDataGrid, "No se ha establecido conexión con el servidor. Obteniendo datos de jUDDI...", DataGridMessage.TIPO_MENSAJE.INFO);
                    if (jUDDIManager.Instance.UpdateURL())
                    {
                        try
                        {
                            buscarTematicas();
                            Utilities.WriteMessageOnGrid(salidaDataGrid,
                                "Temáticas obtenidas correctamente del servidor", DataGridMessage.TIPO_MENSAJE.INFO);
                            hiloActiveMQ.Start();
                            tematicasCambiadas = true;
                        }
                        catch (Exception)
                        {
                            Utilities.WriteMessageOnGrid(salidaDataGrid,
                            "No se han obtenido las temáticas del servidor", DataGridMessage.TIPO_MENSAJE.ERROR);
                        }
                    }
                    else
                        Utilities.WriteMessageOnGrid(salidaDataGrid,
                        "No se han obtenido las temáticas del servidor", DataGridMessage.TIPO_MENSAJE.ERROR);
                }
            }
        }

        private void workerTematicas_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (tematicasCambiadas)
                auditoria.Mensaje(new object[] { }, TiposAuditoria.Ordinal(TiposAuditoria.TIPO_AUDITORIA.CAMBIAR_TEMATICAS), usuario.Id);
            else
                auditoria.Mensaje(new object[] { }, TiposAuditoria.Ordinal(TiposAuditoria.TIPO_AUDITORIA.ERROR_CAMBIAR_TEMATICAS), usuario.Id);

            System.Threading.Thread.Sleep(1000);
        }

        private void workerjUDDI_DoWork(object sender, DoWorkEventArgs e)
        {
            Dispatcher.Invoke((SetStatusCallback)delegate
            {
                SetStatusjUDDI(null);
            }, null);
            conectadojUDDI = jUDDIManager.Instance.GetAuthToken();
        }

        private void workerjUDDI_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            SetStatusjUDDI(conectadojUDDI);
        }

        private void workerPeticiones_DoWork(object sender, DoWorkEventArgs e)
        {
            if (gestor.HayPeticionesPendientes())
                gestor.sendMessages();
        }

        private void workerPeticiones_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            Utilities.WriteMessageOnGrid(salidaDataGrid, "No hay más peticiones pendientes de enviar", DataGridMessage.TIPO_MENSAJE.INFO);
        }

        private void workerPeticionesMQ_DoWork(object sender, DoWorkEventArgs e)
        {
            if (gestor.HayPeticionesPendientesMQ())
                gestor.sendMessagesMQ();
        }

        private void workerPeticionesMQ_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            Utilities.WriteMessageOnGrid(salidaDataGrid, "No hay más mensajes ActiveMQ pendientes de enviar", DataGridMessage.TIPO_MENSAJE.INFO);
        }
        #endregion

        #region Eventos de los botones de la barra de tareas superior
        private void miVerRolesUsuarios_Click(object sender, RoutedEventArgs e)
        {
            ShowPage<ucUserRoles>();
        }

        private void miVerGrupos_Click(object sender, RoutedEventArgs e)
        {
            ShowPage<ucGruposRoles>();
        }

        private void miAuditoria_Click(object sender, RoutedEventArgs e)
        {
            ShowPage<ucAuditoria>();   
        }

        private void miBorrarDatosServer_Click(object sender, RoutedEventArgs e)
        {
            StopThreads();
            ServerConnData.Instance.Clear();
            TematicasData.Instance.Clear();
        }

        private void miClientes_Click(object sender, RoutedEventArgs e)
        {
            ShowPage<ucClientes>();
        }

        private void miObras_Click(object sender, RoutedEventArgs e)
        {
            ShowPage<ucObras>();
        }

        private void miSubastas_Click(object sender, RoutedEventArgs e)
        {
            ShowPage<ucSubastas>();
        }

        public void miUsuario_Click(object sender, RoutedEventArgs e)
        {
            ucUserData uc;

            if (FindDocumentContent(typeof(ucUserData)) == null)
            {
                uc = new ucUserData(usuario);
                uc.UsuarioCAD = uCAD;
                ShowPage<ucUserData>(uc);
            }
            else
                Xceed.Wpf.Toolkit.MessageBox.Show("Ya hay abierta una ventana de creación o edición de usuarios. Ciérrela antes de abrir otra.",
                    "Error", MessageBoxButton.OK, MessageBoxImage.Error);
        }

        private void miAdministracion_Click(object sender, RoutedEventArgs e)
        {
            ShowPage<ucAdmin>();
        }

        private void miAbout_Click(object sender, RoutedEventArgs e)
        {
            new AboutBoxNET().ShowDialog();
        }

        private void miSalir_Click(object sender, RoutedEventArgs e)
        {
            miCerrarSesion_Click(sender, e);
        }

        private void miConfiguracion_Click(object sender, RoutedEventArgs e)
        {
            ConfigWindow config;

            if (Xceed.Wpf.Toolkit.MessageBox.Show("¿Desea modificar la configuración de la conexión local?\nSe cerrarán todas las ventanas abiertas y su sesión de usuario",
                    "Cambiar configuración", MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes)
            {
                config = new ConfigWindow(usuario.Id);

                // Cerrar todos los hijos

                Hide();
                config.ShowDialog();

                if (config.Success == null || config.Success == true) // Volver a pedir el usuario
                {
                    new MainWindow().Show();
                    Close();
                }
                else if (config.Success == false)
                {
                    usuario = null;
                    Show();
                    lbUsuarioConectado.Content = "No hay conexión con la base de datos local";
                    miClientes.IsEnabled = miObras.IsEnabled = miSubastas.IsEnabled = miUsuario.IsEnabled =
                        miAdministracion.IsEnabled = false;
                }
            }
        }

        private void miBorrarDatosUser_Click(object sender, RoutedEventArgs e)
        {
            if (Xceed.Wpf.Toolkit.MessageBox.Show("¿Desea borrar sus datos almacenados de la aplicación?",
                "Borrar datos de usuario", MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes)
            {
                UserConnData.Instance.Clear();
            }
        }

        private void miBorrarDatosDB_Click(object sender, RoutedEventArgs e)
        {
            if (Xceed.Wpf.Toolkit.MessageBox.Show("¿Desea borrar los datos de conexión local de la aplicación?",
                    "Borrar datos de conexión local", MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes)
            {
                DBConnData.Instance.Clear();
            }
        }

        private void miCerrarSesion_Click(object sender, RoutedEventArgs e)
        {
            if (Xceed.Wpf.Toolkit.MessageBox.Show("¿Desea cerrar la sesión?",
                "Cerrar sesión", MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes)
            {
                new MainWindow().Show();
                Close();
            }
        }

        private void miTematicas_Click(object sender, RoutedEventArgs e)
        {
            TematicasWindow window = new TematicasWindow();

            window.ShowDialog();
            if (window.Success == true)
            {
                // Paramos el hilo por lo que pueda pasar. El hilo muere y habrá que crear otro
                StopActiveMQ();
                // Creamos el nuevo hilo de escucha y arrancamos
                SetStatusActiveMQ(null);

                auditoria.Mensaje(new object[] { },
                    TiposAuditoria.Ordinal(TiposAuditoria.TIPO_AUDITORIA.CAMBIAR_TEMATICAS), usuario.Id);
                System.Threading.Thread.Sleep(1000);
                hiloActiveMQ = new Thread(ListenerMQ);
                if (TematicasData.Instance.Tematicas != null &&
                        TematicasData.Instance.Tematicas.Count > 0)
                    hiloActiveMQ.Start();
                else
                    workerTematicas.RunWorkerAsync();
            }
        }

        private void miConfigServer_Click(object sender, RoutedEventArgs e)
        {
            ConfigServerWindow window = new ConfigServerWindow(usuario.PseudonimoLocal, usuario.Id);
           
            window.ShowDialog();

            if (window.Success == true)
            {
                StopThreads();
                SetStatusActiveMQ(null);

                hiloActiveMQ = new Thread(ListenerMQ);
                if (TematicasData.Instance.Tematicas != null &&
                            TematicasData.Instance.Tematicas.Count > 0)
                    hiloActiveMQ.Start();
                else
                    workerTematicas.RunWorkerAsync();

                workerjUDDI.RunWorkerAsync();
                if (gestor.HayPeticionesPendientes())
                    workerPeticiones.RunWorkerAsync();
            }  
        }
        #endregion

        #region Métodos de mostrar pestañas
        private DocumentContent FindDocumentContent(Type t)
        {
            // Buscamos si hay abierta una instancia del documento a abrir
            foreach (AvalonDock.DocumentContent doc in dockManager.Documents)
            {
                if (doc.Content.GetType() == t)
                    return doc;
            }
            return null;
        }

        /// <summary>
        /// Método que se encarga de mostrar una nueva pestaña con el control de usuario correspondiente
        /// </summary>
        /// <typeparam name="T">Tipo de dato recibido</typeparam>
        public void ShowPage<T>(T obj = null) where T : UserControl
        {
            object item;
            bool exists = false;
            int index = -1;
            DocumentContent content, activo = null;
            UserControl uc = null;
            DocumentPane panelActivo = null;

            // Cogemos el panel del control (si existe)
            foreach (ManagedContent m in dockManager.Documents)
            {
                if (m is DocumentContent)
                {
                    if (m.Content.GetType() == typeof(T))
                    {
                        panelActivo = (DocumentPane)m.ContainerPane;
                        activo = (DocumentContent)m;
                        exists = true;
                        break;
                    }
                }
            }

            // Si el panel existe, buscamos la posición correspondiente del elemento en dicho panel
            if (exists)
            {
                for (int i = 0; i < panelActivo.Items.Count; i++)
                {
                    item = panelActivo.Items[i];
                    if (item is DocumentContent)
                    {
                        content = ((DocumentContent)item);
                        if (content.Content.GetType() == typeof(T))
                        {
                            index = i;
                            exists = true;
                            break;
                        }
                    }
                }

                dockManager.ActiveDocument = activo;
            }
            else // Si no existe, hay que buscar un panel donde insertarlo
            {
                if (dockManager.ActiveDocument != null && (dockManager.ActiveDocument).ContainerPane != null)
                    panelActivo = (DocumentPane)(dockManager.ActiveDocument).ContainerPane;
                else
                    panelActivo = dockPanel;

                content = new DocumentContent();

                if (obj == null)
                {
                    uc = Activator.CreateInstance<T>();
                    content.Content = uc;
                }
                else
                {
                    uc = obj;
                    content.Content = uc;
                }
                content.Title = GetTitle(uc);

                // Añadir en una posición intermedia
                if (!panelActivo.Items.IsEmpty && panelActivo.SelectedIndex != panelActivo.Items.Count - 1)
                {
                    panelActivo.Items.Insert(panelActivo.SelectedIndex + 1, content);
                    panelActivo.SelectedIndex = panelActivo.SelectedIndex + 1;
                }
                else
                {
                    panelActivo.Items.Add(content);
                    panelActivo.SelectedIndex = panelActivo.Items.Count - 1;
                }

                AddHandler(uc);
            }   
        }

        /// <summary>
        /// Método que devuelve el título de la pestaña a mostrar
        /// </summary>
        /// <param name="uc">Control de usuario del que sacar el título</param>
        /// <returns>Título del control de usuario</returns>
        private string GetTitle(UserControl uc)
        {
            List<Type> tipos = new List<Type>(){typeof(ucAdmin), typeof(ucSubastas), typeof(ucObras),
            typeof(ucClientes), typeof(ucUserData), typeof(ucObraData), typeof(ucClientData), typeof(ucSubastaData),
            typeof(ucSubastaPujaData), typeof(ucAuditoria), typeof(ucGruposRoles), typeof(ucNuevoGrupo), typeof(ucUserRoles)};
            Type tipoControl;

            tipoControl = uc.GetType();
            if (tipos.Contains(tipoControl))
                return tipoControl.GetProperty("Title", BindingFlags.Public | BindingFlags.Instance).
                    GetGetMethod().Invoke(uc, null).ToString();
            else
                return string.Empty;
        }

        private void AddHandler(UserControl uc)
        {
            List<Type> tipos = new List<Type>(){typeof(ucAdmin), typeof(ucUserData), typeof(ucObraData), typeof(ucClientData),
                typeof(ucSubastaData), typeof(ucSubastaPujaData), typeof(ucUserRoles)};
            Type tipoControl;

            tipoControl = uc.GetType();

            if (tipos.Contains(tipoControl))
                tipoControl.GetMethod("AddEventHandler", BindingFlags.Public | BindingFlags.Instance).Invoke(uc, null);
        }
        #endregion

        #region Métodos de los comandos de ayuda
        protected void HelpCanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = true;
        }

        protected void HelpExecuted(object sender, ExecutedRoutedEventArgs e)
        {
            System.Diagnostics.Process.Start("http://server1234/myapplication/help/home.aspx");
        }
        #endregion

        #region Métodos de trabajo con ActiveMQ
        private void ListenerMQ()
        {
            List<string> destinos;
            
            destinos = TematicasData.Instance.Tematicas;
            try
            {
                SetSubscribers();
            }
            catch (Exception)
            {
                try
                {
                    salidaDataGrid.Dispatcher.Invoke((SetStatusCallback)delegate()
                    {
                        DataGridMessage mens = new DataGridMessage(DateTime.Now, "No ha sido posible conectar con el servidor. Pidiendo datos al servidor jUDDI", DataGridMessage.TIPO_MENSAJE.INFO);
                        ((DataGrid)salidaDataGrid.Content).Items.Add(mens);
                    });
                    
                    if (jUDDIManager.Instance.UpdateURL())
                        SetSubscribers();
                }
                catch (Exception)
                {
                    SetStatusActiveMQ(false);
                }
            }
        }

        private void SetSubscribers()
        {
            List<string> destinos;
            ActiveMQSubscriber subscriber;

            destinos = TematicasData.Instance.Tematicas;
            subscribers.Clear();
            subscriber = new ActiveMQSubscriber("Ventas", ServerConnData.Instance.ActiveMQURL, "Subscriber .NET Ventas", "Subscriber .NET Ventas");
            subscriber.OnMessageReceived += new MessageReceivedDelegate(subscriber_OnMessageReceived);
            subscribers.Add(subscriber);
            subscriber = new ActiveMQSubscriber("SubastasActivas", ServerConnData.Instance.ActiveMQURL, "Subscriber .NET SubastasActivas", "Subscriber .NET SubastasActivas");
            subscriber.OnMessageReceived += new MessageReceivedDelegate(subscriber_OnMessageReceived);
            subscribers.Add(subscriber);

            if (destinos == null || destinos.Count <= 0)
            {
                Dispatcher.Invoke((SetStatusCallback)delegate
                {
                    SetStatusActiveMQ(false);
                });
            }
            else
            {
                foreach (string s in destinos)
                {
                    subscriber = new ActiveMQSubscriber(s, ServerConnData.Instance.ActiveMQURL, "Subscriber .NET " + s, "Subscriber .NET " + s);
                    subscriber.OnMessageReceived += new MessageReceivedDelegate(subscriber_OnMessageReceived);
                    subscribers.Add(subscriber);
                }
                SetStatusActiveMQ(true);
                this.semaphore.WaitOne();
            }
        }

        private void subscriber_OnMessageReceived(ActiveMQMessage message)
        {
            string mens, from;

            if (message is ActiveMQMapMessage)
            {
                if (((ActiveMQMapMessage)message).Body.Contains("mensaje"))
                {
                    from = ((ActiveMQTopic)(message.FromDestination)).TopicName;
                    mens = ((ActiveMQMapMessage)message).Body.GetString("mensaje");

                    if (from.Equals("Pintura") || from.Equals("Escultura") ||
                        from.Equals("Renacimiento") || from.Equals("Barroco"))
                    {
                        if (mens.Equals("publicarSubasta"))
                        {
                            Utilities.WriteMessageOnGrid(salidaDataGrid, "[Active MQ: " + from + "]\tSe ha publicado una nueva subasta con referencia "
                            + ((ActiveMQMapMessage)message).Body.GetLong("referencia"), DataGridMessage.TIPO_MENSAJE.INFO, (ActiveMQMapMessage)message);
                            auditoria.Mensaje(new object[] { ((ActiveMQMapMessage)message).Body.GetLong("referencia") },
                                TiposAuditoria.Ordinal(TiposAuditoria.TIPO_AUDITORIA.RECIBIR_PUBLICACION_SUBASTA), usuario.Id);
                            System.Threading.Thread.Sleep(1000);
                            gestor.addMessageMQ((ActiveMQMapMessage)message);
                        }
                        else if (mens.Equals("actualizarSubasta"))
                        {
                            auditoria.Mensaje(new object[] { ((ActiveMQMapMessage)message).Body.GetLong("referencia") },
                                TiposAuditoria.Ordinal(TiposAuditoria.TIPO_AUDITORIA.RECIBIR_MODIFICACION_SUBASTA), usuario.Id);
                            System.Threading.Thread.Sleep(1000);
                            Utilities.WriteMessageOnGrid(salidaDataGrid, "[Active MQ: " + from + "]\tSe ha actualizado la subasta con referencia " + ((ActiveMQMapMessage)message).Body.GetLong("referencia"),
                            DataGridMessage.TIPO_MENSAJE.INFO);
                        }
                    }
                    else if (from.Equals("SubastasActivas"))
                    {
                        if (mens.Equals("activarSubasta"))
                        {
                            auditoria.Mensaje(new object[] { ((ActiveMQMapMessage)message).Body.GetLong("referencia") },
                                TiposAuditoria.Ordinal(TiposAuditoria.TIPO_AUDITORIA.RECIBIR_ACTIVACION_SUBASTA), usuario.Id);
                            System.Threading.Thread.Sleep(1000);
                            Utilities.WriteMessageOnGrid(salidaDataGrid, "[Active MQ: " + from + "]\tSe ha activado la nueva subasta con referencia "
                                + ((ActiveMQMapMessage)message).Body.GetLong("referencia"), DataGridMessage.TIPO_MENSAJE.INFO);
                        }

                        else if (mens.Equals("actualizarPujaMaxima"))
                        {
                            auditoria.Mensaje(new object[] { ((ActiveMQMapMessage)message).Body.GetLong("referencia") },
                                TiposAuditoria.Ordinal(TiposAuditoria.TIPO_AUDITORIA.RECIBIR_PUJA), usuario.Id);
                            System.Threading.Thread.Sleep(1000);
                            Utilities.WriteMessageOnGrid(salidaDataGrid, "[Active MQ: " + from + "]\tSe ha actualizado la puja máxima de la subasta con referencia "
                                + ((ActiveMQMapMessage)message).Body.GetLong("referencia"), DataGridMessage.TIPO_MENSAJE.INFO);
                        }
                        else if (mens.Equals("actualizarSubasta"))
                        {
                            auditoria.Mensaje(new object[] { ((ActiveMQMapMessage)message).Body.GetLong("referencia") },
                                TiposAuditoria.Ordinal(TiposAuditoria.TIPO_AUDITORIA.RECIBIR_MODIFICACION_SUBASTA), usuario.Id);
                            System.Threading.Thread.Sleep(1000);
                            Utilities.WriteMessageOnGrid(salidaDataGrid, "[Active MQ: " + from + "]\tSe ha actualizado la subasta con referencia " + ((ActiveMQMapMessage)message).Body.GetLong("referencia"),
                                DataGridMessage.TIPO_MENSAJE.INFO);
                        }
                        else if (mens.Equals("cancelarSubasta"))
                        {
                            auditoria.Mensaje(new object[] { ((ActiveMQMapMessage)message).Body.GetLong("referencia") },
                                TiposAuditoria.Ordinal(TiposAuditoria.TIPO_AUDITORIA.RECIBIR_CANCELACION_SUBASTA), usuario.Id);
                            System.Threading.Thread.Sleep(1000);
                            Utilities.WriteMessageOnGrid(salidaDataGrid, "[Active MQ: " + from + "]\tSe ha cancelado la subasta con referencia " + ((ActiveMQMapMessage)message).Body.GetLong("referencia"),
                                DataGridMessage.TIPO_MENSAJE.INFO);
                        }
                    }
                    else if (from.Equals("Ventas"))
                    {
                        if (mens.Equals("finalizarSubasta"))
                        {
                            auditoria.Mensaje(new object[] { ((ActiveMQMapMessage)message).Body.GetLong("referencia") },
                                TiposAuditoria.Ordinal(TiposAuditoria.TIPO_AUDITORIA.RECIBIR_FINALIZACION_SUBASTA), usuario.Id);
                            System.Threading.Thread.Sleep(1000);
                            Utilities.WriteMessageOnGrid(salidaDataGrid, "[Active MQ: " + from + "]\tSe ha finalizado la nueva subasta con referencia "
                                + ((ActiveMQMapMessage)message).Body.GetLong("referencia"), DataGridMessage.TIPO_MENSAJE.INFO);
                        }
                    }
                }
            }
        }

        private void SetStatusActiveMQ(bool? state)
        {
            IntPtr b;
            BitmapSource bs;

            Dispatcher.Invoke((SetStatusCallback)delegate
            {
                if (state != null)
                {
                    lbConectadoMQ.Content = state == true ? "Conectado a ActiveMQ" : "No conectado a ActiveMQ";
                    b = state == true ? Properties.Resources.verde.GetHbitmap() : Properties.Resources.rojo.GetHbitmap();
                }
                else
                {
                    lbConectadoMQ.Content = "Estableciendo conexión con ActiveMQ";
                    b = Properties.Resources.YellowSphere.GetHbitmap();    
                }
                bs = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(b, IntPtr.Zero, Int32Rect.Empty,
                        System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());
                imgConnection.Source = bs;
            }, null);
        }

        private void SetStatusjUDDI(bool? state)
        {
            IntPtr b;
            BitmapSource bs;

            Dispatcher.Invoke((SetStatusCallback)delegate
            {
                if (state != null)
                {
                    lbConectadojUDDI.Content = state == true ? "Conectado a jUDDI" : "No conectado a jUDDI";
                    b = state == true ? Properties.Resources.verde.GetHbitmap() : Properties.Resources.rojo.GetHbitmap();
                }
                else
                {
                    lbConectadojUDDI.Content = "Conectando con jUDDI...";
                    b = Properties.Resources.YellowSphere.GetHbitmap(); 
                }
                bs = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(b, IntPtr.Zero, Int32Rect.Empty,
                        System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());
                imgConnectionUDDI.Source = bs;
            }, null);
        }

        public void AddMessage(IMessageType mensaje)
        {
            gestor.addMessageWS(mensaje);
            if (gestor.HayPeticionesPendientes() && !workerPeticiones.IsBusy)
                workerPeticiones.RunWorkerAsync();
        }

        public void AddMessageMQ(ActiveMQMapMessage mensaje)
        {
            gestor.addMessageMQQueue(mensaje);
            if (gestor.HayPeticionesPendientesMQ() && !workerPeticionesMQ.IsBusy)
                workerPeticionesMQ.RunWorkerAsync();
        }

        public void StopActiveMQ()
        {
            // Si el hilo está vivo, libéralo y dale la orden de que acabe...
            if (hiloActiveMQ.IsAlive)
            {
                try
                {
                    semaphore.Release(); // Liberación del semáforo
                }
                catch (Exception)
                { }

                while (!hiloActiveMQ.ThreadState.HasFlag(ThreadState.Stopped))
                {
                    System.Threading.Thread.Sleep(500);
                }
            }
            // Para todos los listeners de ActiveMQ
            foreach (ActiveMQSubscriber s in subscribers)
                s.Dispose();

            subscribers.Clear(); // Vacía la lista de listeners  
        }

        public void WaitForjUDDI()
        {
            // Espérate a que el BackgroundWorker de jUDDI acabe
            while (workerjUDDI.IsBusy)
                System.Threading.Thread.Sleep(500);
        }

        public void StopThreads()
        {
            SetStatusActiveMQ(false);
            SetStatusjUDDI(false);
            StopActiveMQ();            
            WaitForjUDDI();            
        }

        public void TestActiveMQConnection()
        {
            IConnectionFactory connectionFactory;
            IConnection connection;
            ISession session;

            connectionFactory = new ConnectionFactory(ServerConnData.Instance.ActiveMQURL);
            connection = connectionFactory.CreateConnection();
            connection.RequestTimeout = TimeSpan.FromSeconds(ModeloGaleriaNET.Properties.Settings.Default.TimeOut);
            connection.ClientId = "ActiveMQ test";
            connection.Start();
            session = connection.CreateSession();
            session.Dispose();
            connection.Dispose();
        }
        #endregion
    }
}